瀏覽器提供的計時器功能有 setTimeout和setInterval二種,我們用它們來延遲一段時間才執行一段程式。
計時器並不是 JavaScript 的功能,而是隸屬於window物件底下的方法,因此在撰寫程式碼時,可省略window物件名稱。會這樣說是因為在 Node.js 環境下也有計時器的功能,方法的名稱也是一樣,但作用和瀏覽器有一些不一樣的地方。這裡我們專注在探討瀏覽器的計時器。
var timeoutID = setTimeout(function(){}, 1000);
var intervalID = setInterval(function(){}, 1000)
clearTimeout(timeoutID);
clearInterval(intervalID);
建立計時器的方式都是先呼叫方法,再代入一個函式,以及一個時間,時間是以毫秒為單位,1秒鐘就是1000毫秒。
提到計時器一定要和前一篇文章的 event loop 一起來看。
console.log("start");
(function(){
	console.log("bar");
	setTimeout(function(){
		console.log("foo");
	}, 0);
})();
console.log("end");
在上面的範例中,或許有人會認為 console 中的訊息是:
"start"
"bar"
"foo"
"end"
立即函式跑完"bar"之後,因為setTimeout延遲的時間是0,所以立刻執行。事實上 console 訊息卻是這樣:
"start"
"bar"
"end"
"foo"
從 event loop 模型來看,整段程式在執行時正佔據 JavaScript call stack,setTimeout事件會被瀏覽器接手,在時間到期時,將函式丟到 task queue 裡,在這裡的任務一定會等到 call stack 的任務完全清空後,才由 event loop 將排第一個的任務移到 call stack 執行。
"start", "bar", "end"會先執行完,然後才由 event loop 從 task queue 裡把"foo"叫到 call stack。
setTimeout和setInterval都會回傳一個計時器ID,我們可以使用clearTimeout和clearInterval二個方法清除計時器,只要代入ID值,但是要在計時器有效的狀態。也就是說一旦setTimeout時間到把函式排進 task queue 之後,它就功成身退,這時也沒有必要再清除它。
雖然setTimeout和setInterval都會將函式排進 task queue 裡,但是它們有不同的地方。
setInterval的計時器在設定的時間到的時候,會將函式排進 task queue 裡,但是如果 task queue 裡已經有上一次計時器排入的任務,setInterval就不會再安排新的任務進去,繼續它的計時。如果是setTimeout在函式裡又再回呼自己的話,還是會將函式排入 task queue。